﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

namespace Microsoft.Mtool.FSM
{
    public class Tour : ICloneable
    {
        private State entry;
        private List<Action> actions = new List<Action>();
        private string id;
        
        private static int idCounter;
        public static void ResetIdCounter()
        {
            idCounter = 0;
        }

        public Tour()
        {
            id = (idCounter++).ToString();
        }

        public Tour(State entry)
            :this()
        {
            this.entry = entry;
        }

        public void Apply(Action action)
        {
            if(Exit != action.FromState)
                throw new Exception("Invalid action applied to state!");
            actions.Add(action);       
        }

        public State Entry
        {
            get
            {
                return actions.Count == 0 ? entry : actions[0].FromState;
            }
        }

        public State Exit
        {
            get 
            {
                return actions.Count == 0 ? entry : actions[actions.Count - 1].ToState;
            }
        }

        public string ID
        {
            get { return id; }
            set { id = value; }
        }

        public List<Action> Actions
        {
            get { return actions; }
        }

        public override string ToString()
        {
            if (entry == null || actions.Count == 0)
                return "";

            StringBuilder sb = new StringBuilder();
            sb.Append("[" + id + "]");
            sb.Append("(" + actions[0].FromState.Id + ")");

            foreach (Action act in actions)
            {
                sb.Append(" " + act.Id + " ");
                sb.Append("(" + act.ToState.Id + ")");
            }
            return sb.ToString();
        }

        public object Clone()
        {
            Tour t = new Tour();
            t.entry = entry;
            t.actions.InsertRange(0, actions);
            return t;
        }
    }
}
